/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.rockyang.dike.utils;


import org.rockyang.dike.core.SubjectManager;
import org.rockyang.dike.core.impl.AuthorizationManager;

import java.util.HashMap;
import java.util.Map;


/**
 * A ThreadContext provides a means of binding and unbinding objects to the
 * current thread based on key/value pairs.
 * 线程工具，为当前线程绑定或者解绑数据（键/值数据对）
 * @author yangjian
 */
public abstract class ThreadContext {

    public static final String AUTHORIZE_MANAGER_KEY = ThreadContext.class.getName() + "_AUTHORIZE_MANAGER_KEY";
    private static final ThreadLocal<Map<Object, Object>> resources = new InheritableThreadLocalMap<>();

    protected ThreadContext() {}

    /**
     * 获取数据
     * @param key
     * @return
     */
    private static Object get(Object key) {
        Map<Object, Object> perThreadResources = resources.get();
        return perThreadResources != null ? perThreadResources.get(key) : null;
    }

    /**
     * 初始化线程存储资源
     */
    private static void initResouces(){
        if (null == resources.get()){
           resources.set(new HashMap<>(16));
        }
    }

    /**
     * 添加数据
     * @param key
     * @param value
     */
    public static void put(Object key, Object value) {

        if (null == key) {
            remove(key);
            return;
        }

        initResouces();
        resources.get().put(key, value);
    }

    /**
     * Unbinds the value for the given <code>key</code> from the current
     * thread.
     *
     * @param key The key identifying the value bound to the current thread.
     * @return the object unbound or <tt>null</tt> if there was nothing bound
     *         under the specified <tt>key</tt> name.
     */
    public static Object remove(Object key) {

        Map<Object, Object> perThreadResources = resources.get();
        Object value = perThreadResources != null ? perThreadResources.remove(key) : null;
        return value;

    }

    public static SubjectManager getAuthorizationManager() {
        return (AuthorizationManager) get(AUTHORIZE_MANAGER_KEY);
    }


    /**
     * 绑定授权认证管理对象
     * @param authorizationManager
     */
    public static void bindAuthorizationManager(SubjectManager authorizationManager) {
        if (null != authorizationManager) {
            put(AUTHORIZE_MANAGER_KEY, authorizationManager);
        }
    }

    /**
     * 当前线程存储类
     * @param <T>
     */
    private static final class InheritableThreadLocalMap<T extends Map<Object, Object>> extends InheritableThreadLocal<Map<Object, Object>> {

        @Override
        @SuppressWarnings({"unchecked"})
        protected Map<Object, Object> childValue(Map<Object, Object> parentValue) {
            if (parentValue != null) {
                return (Map<Object, Object>) ((HashMap<Object, Object>) parentValue).clone();
            } else {
                return null;
            }
        }
    }
}

